
document.write("<script type='text/javascript' src='core/common.js'></script>");

function Resources(defaultLang) {
    
    var res = AbstractResource();

    res.init = function init() {
        this.lang["ru"] = {
            TASK    :   "Найти значение определителя ",
            SOLVE2x2:   "Видим, что матрица размера 2x2. Решаем перемножением \"крест-накрест\": "
        }

        this.lang["en"] = {
            TASK    :   "Find the determinant value ",
            SOLVE2x2:   "We see that matrix has the size 2x2. Solve it \"crosswise\" : "
        }
    };

    res.init();   
    res.setLang(defaultLang);
    return res;
};

function TaskDeterminant() {
    this.steps = new Array();
    var nlsRes = "determinant";
    var solved = false;

    // information about inspected column
    function ColInfo() {
        this.message = ""; // message what we will do with column
        this.op = MatrixOperations.NONE; // operation type: swap rows (par1 and par2) / 
                      //                 mul row (par1) by number (par2) / 
                      //                 add row (par1) to another (par2) multiplied by number (par3)
        this.par1;
        this.par2;
        this.par3;
    }

    function OperationStep() {
        var message = "";
        var m; // matrix after operation
        var result;
        this.mul = 1; // multiplier

        this.init = function init(step) {
            if (!step) {
                return;
            }
            this.message = step.message;
            this.m = step.m;
            this.mul = step.mul;
        }

        this.brk = function brk(n) {
            if (n >= 0) {
                return n;
            }
            return "(" + n + ")";
        }

        this.generateResult = function(solved) {
            lm = new LaTeXMatrix(this.m);
            var strmul = "";

            if (!solved) {
                if (this.mul != 1) {
                    strmul = this.brk(this.mul);
                    strmul += "\\cdot";
                }

                this.result = { res : "determinant", name : "STRING", pars : {"par" : "\\(" + strmul + lm.toString() + "\\)" }};
            } else {
                if (this.mul != 1) {
                    strmul += this.brk(this.mul);
                }
                for (var i = 0; i < this.m.cols(); i++) {
                    if (strmul != "" || i > 0) {
                        strmul += "\\cdot";
                    }
                    strmul += this.brk(this.m.e(i + 1, i + 1));
                }
                strmul += " = " + this.mul * this.m.det();
                this.result = { res : "determinant", name : "STRING", pars : {"par" : "\\(" + strmul + "\\)" }};
            }
        }

        this.setMatrix = function(m, solved) {
            this.m = m.dup();
            this.generateResult(solved);
        }
    }

    this.generate = function generate(n, r) {
        this.m = $M([
  [1,-1,-3,-2],
  [0,-2,-6,-4],
  [0,0,4,-1],
  [0,0,2,5]
]);
   //     this.m = iRandomMatrix(n, n, r);
        this.lm = new LaTeXMatrix(this.m);
        this.n = n; // dimension
        this.r = r; // elements will be generated from [-r; r]
        this.multiplier = 1; // matrix multiplier
        this.solved = false;
        this.makeSteps();
    };

    this.analyzeMatrix = function analyzeMatrix() {
        nCol = this.m.cols();
        var lastOpStep;
        if (this.steps.length > 0) {
            lastOpStep = this.steps[this.steps.length - 1];
        }
        for (var i = 1; i <= nCol; i++) {
            colInfo = this.inspectCol(i);
            if (colInfo.op != MatrixOperations.NONE) {
                opstep = new OperationStep();
                opstep.init(lastOpStep);
                gr = new GlobalResources.Matrix();
                mo = new MatrixOperations(this.m);
                switch (colInfo.op) {
                    case MatrixOperations.SWAP: 
                        opstep.message = {res : "matrixops", 
                                          name : "SWAP_ROWS_SHORT", 
                                          hint : "SWAP_ROWS", 
                                          pars : {
                                              row1 : colInfo.par1, 
                                              row2 : colInfo.par2 
                                          }
                        };
                        mo.swapRows(colInfo.par1, colInfo.par2);
                        opstep.mul = -opstep.mul;
                        opstep.setMatrix(this.m, false); 
                        break;
                    case MatrixOperations.ADDMUL:
                        opstep.message = {res : "matrixops", 
                                          name : "MUL_ADD_ROW_SHORT", 
                                          hint : "MUL_ADD_ROW", 
                                          pars : {
                                              rowSrc : colInfo.par1, 
                                              rowDest : colInfo.par2, 
                                              mul : brk(colInfo.par3) 
                                          }
                        };
                        mo.addRows(colInfo.par1, colInfo.par2, colInfo.par3);
                        opstep.setMatrix(this.m, false); 
                        break;
                }
                this.steps.push(opstep);
                return true;
            }
        }

        // matrix is triangular now
        this.solved = true;
        opstep = new OperationStep();
        opstep.init(lastOpStep);
        opstep.message = { res : "determinant", name : "FINISH_TRIANGULAR_SHORT", hint : "FINISH_TRIANGULAR" };
        opstep.setMatrix(this.m, true);
        this.steps.push(opstep);

        return true;

    }

    this.nextStep = function() {
        return this.analyzeMatrix();
    }

    this.inspectCol = function inspectCol(col) {
         column = this.m.col(col);
         elems = new Array();
         for (var i = col; i <= column.dimensions(); i++) {
            elems[i - col] = column.e(i);
         }

         var ci = new ColInfo();

         // check if column has the view (x 0 0 0 0 0 0 0)
         var properCol = true;
         for (var i = 1; i < elems.length; i++) {
             if (elems[i] != 0) {
                 properCol = false;
                 break;
             }
         }
         if (properCol) {
             return ci;
         }

         var g = gcdV(elems);
         // if GCD of column elements is 1 then at the end there will column like (1 0 0 0 0 0)^t
         // if there exist +-g as element
         for (var i = 0; i < elems.length; i++) {
             var e = elems[i];
             if (Math.abs(e) == g) {
                 // if +-g is not located at the first place --> move it by swapping rows
                 if (i > 0) {
                     ci.op = MatrixOperations.SWAP;
                     ci.par1 = col;
                     ci.par2 = col + i;
                     return ci;
                 }
                 else {
                     for (var ind = 1; ind < elems.length; ind++) {
                         if (elems[ind] != 0) {
                             ci.op = MatrixOperations.ADDMUL;
                             ci.par1 = col;
                             ci.par2 = col + ind;
                             ci.par3 = Math.abs(Math.round(elems[ind] / e)); // e = +-g
                             if (elems[ind] * e > 0){
                                ci.par3 = -ci.par3;
                             }
                             return ci;
                         }
                     }
                 }
             }
             
         }

         // if g does not present within elems (ex: 2 3 4 5)
         if (ci.op == MatrixOperations.NONE) {
             // find absolute max and min
            var maxElem = elems[0];
            var maxIndex = 0;
            var minElem = elems[0];
            var minIndex = 0;
            for (var j = 0; j < elems.length; j++) {
                var curElem = elems[j];
                if (curElem == 0) {
                    continue;
                }
                if (minElem == 0) {
                    minElem = curElem;
                    minIndex = j;
                }
                if (Math.abs(maxElem) < Math.abs(curElem)) {
                    maxElem = curElem;
                    maxIndex = j;
                }
                if (Math.abs(minElem) > Math.abs(curElem)) {
                    minElem = curElem;
                    minIndex = j;
                }
            }
            //alert(dump(elems));
            //alert("minElem = " + minElem);
            //alert("minIndex = " + minIndex);
            //alert("maxElem = " + maxElem);
            //alert("maxIndex = " + maxIndex);
            ci.op = MatrixOperations.ADDMUL;
            ci.par1 = col + minIndex;
            ci.par2 = col + maxIndex;
            ci.par3 = Math.abs(Math.round(maxElem / minElem));
            if (maxElem * minElem > 0) {
                ci.par3 = -ci.par3;
            }
         }
             // all elements are differ than +-g. Then substract one element from another which have the smallest absolute difference
             // for example: (2 -3 -6 10) -> elements 2 and -3 have absolute difference = 1

         //s = "Нам необходимо занулить " + col + " колонку. Наибольший общий делитель элементов " + elems + " равен " + g;

         return ci;
    }

    this.makeSteps = function makeSteps() {
        // Generate task string
        this.taskStr = {res : "determinant", 
                        name : "TASK", 
                        pars : {
                            matrix : "\\(" + this.lm.toString() + "\\)."
                        } 
        };
    };


    /*this.solve2x2 = function solve2x2(slM) {
        s = "FINISH_TRIANGULAR";
        lm = new LaTeXMatrix(slM);
        s += "\\[" + lm.toString() + " = " + this.brk(slM.e(1,1)) + "\\cdot " + this.brk(slM.e(2,2)) + "-" + 
                                             this.brk(slM.e(2,1)) + "\\cdot " + this.brk(slM.e(1,2)) + "=" + Math.round(slM.det()) + " \\]";
        return s;
        
    }*/

};

